package com.xinruke.hostels.zuul.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.xinruke.hostels.common.constants.LoginConstants;
import com.xinruke.hostels.common.util.JwtUtil;
import com.xinruke.hostels.common.vo.ResultVO;
import com.xinruke.hostels.manage.user.interfaces.api.ManageUserApi;
import com.xinruke.hostels.manage.user.interfaces.dto.login.LoginManageValidateDTO;
import com.xinruke.hostels.manage.user.interfaces.dto.login.LoginManageValidateResultDTO;
import com.xinruke.hostels.reservation.user.interfaces.api.ReservationUserApi;
import com.xinruke.hostels.reservation.user.interfaces.dto.LoginReservationValidateDTO;
import com.xinruke.hostels.reservation.user.interfaces.dto.LoginReservationValidateResultDTO;
import com.xinruke.hostels.zuul.vo.LoginUrlWhiteVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName LoginFilter
 * @CreateDate 2019/6/16
 * @Author FengXinQiang
 * @Version V1.0.0.0
 * @Decription 登录过滤器
 */
@Component
public class LoginFilter extends ZuulFilter {
    Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    ReservationUserApi reservationUserApi;
    @Autowired
    ManageUserApi manageUserApi;
    @Autowired
    LoginUrlWhiteVO loginUrlWhiteVO;

    /**
     * 过滤器类型选择：
     * pre 为路由前
     * route 为路由过程中
     * post 为路由过程后
     * error 为出现错误的时候
     * 同时也支持static ，返回静态的响应，详情见StaticResponseFilter的实现
     * 以上类型在会创建或添加或运行在FilterProcessor.runFilters(type)
     */
    @Override
    public String filterType() {
        return "pre";
    }

    /**
     * 过滤器顺序，越小越先执行
     *
     * @return 排序的序号
     */
    @Override
    public int filterOrder() {
        return 0;
    }

    /**
     * 过滤器是否生效
     * 返回true代表需要权限校验，false代表不需要用户校验即可访问
     */
    @Override
    public boolean shouldFilter() {
        //不需要登录的地址集合
        Map<String, String> loginUrlWhiteMap = new HashMap<>();

        if (loginUrlWhiteVO != null) {
            if (!loginUrlWhiteVO.isEnabled()) {
                return false;
            }

            //初始化登录白名单
            String url = loginUrlWhiteVO.getWhiteUrl();
            if (!StringUtils.isEmpty(url)) {
                String[] urls = url.split(",");
                for (String u : urls) {
                    loginUrlWhiteMap.put(u, u);
                }
            }
        }

        //获取当前请求上下文
        RequestContext requestContext = RequestContext.getCurrentContext();
        //取出当前请求
        HttpServletRequest request = requestContext.getRequest();

        String requestURI = request.getRequestURI();

        //TODO swagger的内置路径，目前的代码会有问题
        if (requestURI.endsWith(loginUrlWhiteVO.getWhiteSuffix())) {
            return false;
        }
        if (!StringUtils.isEmpty(loginUrlWhiteMap.get(requestURI))) {
            return false;
        }
        return true;
    }

    /**
     * 业务逻辑
     * 只有上面返回true的时候，才会进入到该方法
     */
    @Override
    public Object run() throws ZuulException {
        //获取当前请求上下文
        RequestContext requestContext = RequestContext.getCurrentContext();
        //取出当前请求
        HttpServletRequest request = requestContext.getRequest();

        //登录token
        String token = request.getHeader(LoginConstants.HEADER_TOKEN_NAME);
        String requestURI = request.getRequestURI();
        logger.info("进入访问过滤器，访问的url:{}，访问的方法：{}", requestURI, request.getMethod());

        try {
            if (JwtUtil.isReservationLogin(token)) {
                LoginReservationValidateDTO loginValidateDTO = new LoginReservationValidateDTO();
                loginValidateDTO.setToken(token);
                ResultVO<LoginReservationValidateResultDTO> loginValidateResultDTO = reservationUserApi.loginValidate(loginValidateDTO);
                if (loginValidateResultDTO.getCode() != 1) {
                    String response = "{\"code\": -10100,\"message\": \"no login\"}";
                    requestContext.setSendZuulResponse(false);
                    requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
                    requestContext.setResponseBody(response);
                    requestContext.getResponse().setContentType("application/json;charset=UTF-8");
                    return null;
                }
            } else if (JwtUtil.isManageLogin(token)) {
                LoginManageValidateDTO loginValidateDTO = new LoginManageValidateDTO();
                loginValidateDTO.setToken(token);
                ResultVO<LoginManageValidateResultDTO> loginValidateResultDTO = manageUserApi.loginValidate(loginValidateDTO);
                if (loginValidateResultDTO.getCode() != 1) {
                    String response = "{\"code\": -10200,\"message\": \"no login\"}";
                    requestContext.setSendZuulResponse(false);
                    requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
                    requestContext.setResponseBody(response);
                    return null;
                }
            } else {
                String response = "{\"code\": -10001,\"message\": \"login type error\"}";
                requestContext.setSendZuulResponse(false);
                requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
                requestContext.setResponseBody(response);
                requestContext.getResponse().setContentType("application/json;charset=UTF-8");
                return null;
            }
        } catch (Exception e) {
            logger.error("登录验证异常：", e);

            String response = "{\"code\": -10001,\"message\": \"login validate error\"}";
            requestContext.setSendZuulResponse(false);
            requestContext.setResponseStatusCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
            requestContext.setResponseBody(response);
            requestContext.getResponse().setContentType("application/json;charset=UTF-8");
            return null;
        }

        return null;
    }
}
